home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Storage / Bento / EmbedHdr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  15.5 KB  |  551 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EmbedHdr.cpp
  3.  
  4.     Contains:    Class definition for ODEmbeddedHandlers class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <4>     9/27/96    EL        1353486: document may become write
  13.                                     protected after opening.
  14.          <3>      5/1/96    JA        1213332: Use 68k alignment for persistent
  15.                                     structs.
  16.          <2>     1/15/96    TJ        Cleaned Up
  17.          <8>    10/24/95    jpa        1293441: Bento memory reserve & fatal
  18.                                     container err.
  19.          <7>     5/26/95    VL        1251403: Multithreading naming support.
  20.          <6>     5/11/95    EL        1245113: fix bug of writing out garbage
  21.                                     with buffering.
  22.          <5>      4/7/95    EL        1213321: Use a different buffering scheme.
  23.          <4>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  24.          <3>     8/26/94    EL        #1182275 Allows writing embeded value in
  25.                                     large block to decrease fragmentation.
  26.                                     #1182308 Allows non-byte swapping
  27.                                     format/extract
  28.          <2>     6/18/94    MB        Correct memory includes
  29.          <1>     5/27/94    VL        first checked in
  30.  
  31.     In Progress:
  32.         
  33. */
  34.  
  35. #ifndef    _ODTYPES_
  36. #include "ODTypes.h"
  37. #endif
  38.  
  39. #ifndef _BENTOHDR_
  40. #include "BentoHdr.h"
  41. #endif
  42.  
  43. #ifndef _EMBEDHDR_
  44. #include "EmbedHdr.h"
  45. #endif
  46.  
  47. #ifndef _SESSHDR_
  48. #include "SessHdr.h"
  49. #endif
  50.  
  51. #ifndef _INDHDR_
  52. #include "IndHdr.h"
  53. #endif
  54.  
  55. #ifndef _EXCEPT_
  56. #include "Except.h"
  57. #endif
  58.  
  59. #ifndef _FLIPEND_
  60. #include "FlipEnd.h"
  61. #endif
  62.  
  63. #ifndef __CM_API__
  64. #include "CMAPI.h"
  65. #endif
  66.  
  67. #ifndef _ODMEMORY_
  68. #include "ODMemory.h"
  69. #endif
  70.  
  71. #ifndef _ERRORDEF_
  72. #include "ErrorDef.xh"
  73. #endif
  74.  
  75. #ifndef __STRING__
  76. #include "string.h"        // For strcpy and strcmp
  77. #endif
  78.  
  79. #ifndef _BENTODEF_
  80. #include "BentoDef.h"
  81. #endif
  82.  
  83. #ifndef _SESSHDR_
  84. #include "SessHdr.h"
  85. #endif
  86.  
  87. //==============================================================================
  88. // Scalar Types
  89. //==============================================================================
  90.  
  91. #if PRAGMA_ALIGN_SUPPORTED
  92. #pragma options align=mac68k
  93. #endif
  94.  
  95. struct ContainerLabelFmt {            /* Layout of a container label:            */
  96.  ODUByte magicBytes[8];                /* 8 bytes: the magic byte identifier    */
  97.  ODUShort flags;                    /* 2    the label flag                    */
  98.  ODUShort bufSize;                    /* 2    TOC buffer size / 1024            */
  99.  ODUShort majorVersion;                /* 2    major format version number        */
  100.  ODUShort minorVersion;                /* 2    minor format version number        */
  101.  ODULong tocOffset;                    /* 4    offset to start of TOC            */
  102.  ODULong tocSize;                    /* 4    total byte size of the TOC        */
  103. };
  104. typedef struct ContainerLabelFmt ContainerLabelFmt;
  105.  
  106. #if PRAGMA_ALIGN_SUPPORTED
  107. #pragma options align=reset
  108. #endif
  109.  
  110.  
  111. #pragma segment EmbedHdr
  112.  
  113. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  114. {
  115.     char    *dest = (char *)to + size - 1;
  116.     char    *src = (char *)from;
  117.     
  118.     while (size--)
  119.         *dest-- = *src++;            
  120. }
  121.  
  122. //==============================================================================
  123. // ODEmbeddedHandlers
  124. //==============================================================================
  125.  
  126. ODEmbeddedHandlers::ODEmbeddedHandlers(CMSession session, CMValue parentValue)
  127. {
  128.     fParentValue = parentValue;
  129.     fSession = session;
  130. }
  131.  
  132. ODEmbeddedHandlers::~ODEmbeddedHandlers()
  133. {
  134. }
  135.  
  136. void ODEmbeddedHandlers::Initialize()
  137. {
  138.     ODSByte    typeName[kBentoTypeNameSize];
  139.     
  140.     CMContainer    container   = CMGetValueContainer(fParentValue);
  141.     CMSession    sessionData = CMGetSession(container);
  142.     
  143.     if (sessionData != fSession)
  144.         THROW(kODErrBentoErr);
  145.  
  146.     ODSessionMustHaveCMAllocReserve(container);
  147.     
  148.     CMSetMetaHandler(fSession, kODEmbeddedContainerTypeName, (CMMetaHandler) containerMetahandler);
  149.     
  150.     CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, typeName, kODNULL);
  151.     
  152.     fReverseEndian = 0;                        /* assume same endian-ness            */
  153.     fPosition    = 0;                        /* container not "open" yet            */
  154.     fSize    = 0;                            /* don't know size yet                */
  155. #if kLargeEmbeddedBlock
  156.     fBufferBegin = 0;
  157.     fBuffer = kODNULL;
  158. #endif
  159.     strcpy(fTypeName, typeName);            /* copy in the container typeName    */
  160.  
  161.     ODSessionRestoreCMAllocReserve(container);
  162. }
  163.  
  164. CMSession ODEmbeddedHandlers::GetCMSession()
  165. {
  166.     return fSession;
  167. }
  168.  
  169. CMRefCon ODEmbeddedHandlers::OpenHandler(CMOpenMode mode)
  170. {
  171.     /* Get the size of the value.  For writing it better be 0 and for reading non-zero...    */
  172.     
  173.     fSize = (ODULong) CMGetValueSize(fParentValue);
  174. #if kLargeEmbeddedBlock
  175.     fBufferBegin = fSize;
  176.     fBuffer = (ODSByte *)ODNewPtr(kEmbeddedBlockSize);
  177. #endif    
  178.     /* Check the open mode and do appropriate checks on size. Set appropriate position...    */
  179.     
  180.     if (strcmp((ODSByte*) mode, "wb+") == 0) {                /* writing...    */
  181.         if (fSize != 0) {                                    /* size must be zero    */
  182.             CMError(fSession, "Cannot create embedded container (type \"^0\") for a value that already has data!", fTypeName);
  183.             return (kODNULL);
  184.         }
  185.         fPosition = 0;                                    /* position to 1st free byte    */
  186.     } else if (strcmp((ODSByte*) mode, "rb") == 0) {         /* reading...                    */
  187.         if (fSize == 0) {                                    /* size must be non-zero        */
  188.             CMError(fSession, "Cannot read embedded container (type \"^0\") for a value that doesn't have data!", fTypeName);
  189.             return (kODNULL);
  190.         }
  191.         fPosition = 0;                                    /* position to 1st byte to read            */
  192.     } else if (strcmp((char *)mode, "rb+") == 0)              /* converting or updating...            */
  193.         fPosition = fSize;                                /* size can be anything(position at end)*/
  194.     else {                                                                                /* bad mode...                                                    */
  195.         CMError(fSession, "Invalid embedded container (type \"^0\") open mode (\"^1\")!", fTypeName, (char *)mode);
  196.         return (kODNULL);
  197.     }
  198.     
  199.     return ((CMRefCon) this);
  200. }
  201.  
  202. void ODEmbeddedHandlers::CloseHandler()
  203. {
  204. #if kLargeEmbeddedBlock
  205.     if (fBuffer != kODNULL) {
  206.         TRY
  207.             (void) this->FlushHandler();
  208.         CATCH_ALL
  209.             ODError err = ErrorCode();
  210.             ODDisposePtr(fBuffer);
  211.             fBuffer = kODNULL;
  212.             // it is OK not to write it out if file is locked
  213.             if ((err > wPrErr) || (err < vLckdErr))
  214.                 RERAISE;
  215.         ENDTRY
  216.         ODDisposePtr(fBuffer);
  217.         fBuffer = kODNULL;
  218.     }
  219. #endif
  220. }
  221.  
  222. CMSize ODEmbeddedHandlers::FlushHandler()
  223. {
  224. #if kLargeEmbeddedBlock
  225.     /* write out the data in the buffer */
  226.     if (fBufferBegin != fSize) {
  227.         CMWriteValueData(fParentValue, fBuffer, fBufferBegin, (CMSize) (fSize - fBufferBegin));
  228.         fBufferBegin = fSize;
  229.     }
  230. #endif
  231.     return ((CMSize) 0);
  232. }
  233.  
  234. CMSize ODEmbeddedHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  235. {
  236.     if (mode == kCMSeekSet)
  237.         fPosition = (ODULong) posOff;
  238.     else if (mode == kCMSeekEnd)
  239.         fPosition = (ODSLong) fSize + posOff;
  240.     else
  241.         fPosition = (ODSLong) fPosition + posOff;
  242.             
  243.     return 0;
  244. }
  245.  
  246. CMSize ODEmbeddedHandlers::TellHandler()
  247. {    
  248.     return fPosition;
  249. }
  250.  
  251. CMSize ODEmbeddedHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  252. {
  253.     ODULong    tryToRead = (ODULong) elementSize * (ODULong) theCount;
  254.  
  255. #if kLargeEmbeddedBlock
  256.     ODULong    amountRead = 0;
  257.     
  258.     if (fPosition < fBufferBegin) {
  259.         /* at least some of it on disk */
  260.         if (tryToRead > (fBufferBegin - fPosition)) {
  261.             /* first read from disk, later read from buffer */
  262.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  263.                                                       (CMSize) (fBufferBegin - fPosition));
  264.             if (amountRead != (fBufferBegin - fPosition)) {
  265.                 /* trouble, don't continue */
  266.                 fPosition += amountRead;            /* update position by amount read                */
  267.                 
  268.                 tryToRead = 0;        
  269.             }
  270.             else {
  271.                 fPosition += amountRead;            /* update position by amount read                */
  272.                 tryToRead -= amountRead;
  273.                 buffer = (CMPtr)((char *)buffer + amountRead);
  274.             }
  275.         }
  276.         else { /* it should all be from disk */
  277.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  278.                                                       (CMSize) tryToRead);
  279.             fPosition += amountRead;            /* update position by amount read                */
  280.             
  281.             return ((CMSize) amountRead);        
  282.         }
  283.     }
  284.  
  285.     if ((tryToRead) && (fPosition >= fBufferBegin)) {                /* it may be in the buffer                */
  286.         if (tryToRead > (fSize - fPosition))
  287.             tryToRead = fSize - fPosition;
  288.         ODBlockMove(fBuffer+fPosition-fBufferBegin, buffer, tryToRead);
  289.         amountRead += tryToRead;
  290.         fPosition += tryToRead;
  291.     }
  292.     
  293.     return ((CMSize) amountRead);        
  294.     
  295. #else
  296.     tryToRead = (ODULong) CMReadValueData(fParentValue,     
  297.                                             buffer,
  298.                                             fPosition, 
  299.                                             (CMSize) tryToRead);
  300.     
  301.     fPosition += tryToRead;                        /* update position by amount read                */
  302.     
  303.     return ((CMSize) tryToRead);        
  304. #endif
  305. }
  306.  
  307. CMSize ODEmbeddedHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  308. {
  309.     ODULong tryWriteAmount = (ODULong) elementSize * (ODULong) theCount;
  310. #if kLargeEmbeddedBlock
  311.     ODULong amountWritten = 0;
  312.     
  313.     /* if there is any data in the portion that is already on disk, write those out first */
  314.     if (fPosition < fBufferBegin) {
  315.         if ((fPosition + tryWriteAmount) > fBufferBegin) { /* it goes over to the buffer */
  316.             amountWritten = fBufferBegin - fPosition;
  317.             tryWriteAmount -= amountWritten;
  318.         }
  319.         else {
  320.             amountWritten = tryWriteAmount;
  321.             tryWriteAmount = 0;
  322.         }
  323.         CMWriteValueData(fParentValue, buffer, fPosition, amountWritten);
  324.         fPosition += amountWritten;
  325.         buffer = (CMPtr)((char *)buffer + amountWritten);
  326.     }
  327.     
  328.     /* if there is any that should go into the buffer or extend to the buffer, move them there */
  329.     
  330.     while (tryWriteAmount > 0) {
  331.         if ((fPosition + tryWriteAmount) <= (fBufferBegin + kEmbeddedBlockSize)) {
  332.             /* we can put everything into the buffer                                        */
  333.             ODBlockMove(buffer, fBuffer + fPosition - fBufferBegin, tryWriteAmount);
  334.             amountWritten += tryWriteAmount;
  335.             fPosition += tryWriteAmount;
  336.             if (fPosition > fSize)
  337.                 fSize = fPosition;
  338.             tryWriteAmount = 0;        /* so we are done */            
  339.         }
  340.         else {
  341.             /* we go beyond the end of the buffer, so we cannot put there directly */
  342.             if (fBufferBegin < fSize) {
  343.                 /* if there are data in the buffer, flush it first, maybe there is room afterwards */
  344.                 (void) this->FlushHandler();
  345.             }
  346.             else {
  347.                 /* there is no data in buffer, yet it does not fit, so just write it out directly */
  348.                 CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  349.                 amountWritten += tryWriteAmount;
  350.                 fPosition += tryWriteAmount;
  351.                 fSize = fPosition;
  352.                 fBufferBegin = fSize;
  353.                 tryWriteAmount = 0;        /* so we are done */            
  354.             }
  355.         }
  356.     }
  357.     return amountWritten;
  358. #else
  359.     CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  360.     fPosition += tryWriteAmount;                    /* update position by amount written    */
  361.  
  362.     if (fPosition > fSize)                        /* if writing past end of value...        */
  363.         fSize = fPosition;                        /* ...set new value size                */
  364.     
  365.     return tryWriteAmount;
  366. #endif
  367.     
  368. }
  369.  
  370. CMEofStatus ODEmbeddedHandlers::EOFHandler()
  371. {
  372.     return ((CMEofStatus) kODFalse);
  373. }
  374.  
  375. CMBoolean ODEmbeddedHandlers::TruncHandler(CMSize containerSize)
  376. {
  377.     if ((ODULong)containerSize <= fSize) {
  378. #if kLargeEmbeddedBlock
  379.         /* only need actually to delete if end result is nothing in the buffer */
  380.         if ((ODULong)containerSize <= fBufferBegin) {
  381.             ODULong    amountToDelete;
  382.             if (fSize > fBufferBegin)
  383.                 amountToDelete = fBufferBegin - (ODULong) containerSize;        /* don't delete amount in buffer */
  384.             else
  385.                 amountToDelete = fSize - (ODULong) containerSize;            /* else delete from end */
  386.             CMDeleteValueData(fParentValue,  (CMCount) containerSize, (CMSize) amountToDelete);
  387.             fBufferBegin = (ODULong) containerSize;        /* so it would match fSize => empty buffer */
  388.         }
  389. #else
  390.     CMDeleteValueData(fParentValue,                                         
  391.                         (CMCount) containerSize,
  392.                         (CMSize) (fSize - (ODULong) containerSize));
  393. #endif
  394.         fSize    = (ODULong) containerSize;    
  395.     
  396.         return kODTrue;
  397.     }
  398.     else
  399.         return kODFalse;
  400. }
  401.  
  402. CMSize ODEmbeddedHandlers::ContainerSizeHandler()
  403. {
  404.     fPosition = fSize;                        /* moral equivalent of seek/tell    */
  405.     
  406.     return ((CMSize) fSize);
  407. }
  408.  
  409. void ODEmbeddedHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  410.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  411.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  412.                                      CMSize *tocOffset, CMSize *tocSize)
  413. {
  414.     ODULong            labelSize;
  415.     ContainerLabelFmt    theLabel;
  416.  
  417.     /* Seek to the end of the label at the end of the value and read it...                                */
  418.     
  419.     this->SeekHandler(-(ODSLong)sizeof(ContainerLabelFmt), kCMSeekEnd);
  420.     labelSize = (ODULong) this->ReadHandler((CMPtr) &theLabel,
  421.                                                 (CMSize) sizeof(ODUByte),
  422.                                                 (CMCount) sizeof(ContainerLabelFmt));
  423.     
  424.     if (labelSize != sizeof(ContainerLabelFmt)) {        /* must have read it all!                            */
  425.         CMError(fSession, "Embedded container (type \"^0\") label could not be read!", fTypeName);
  426.         return;
  427.     }
  428.     
  429.     /* Return all the label info...                                                                                                                */
  430.     
  431.     ODBlockMove(theLabel.magicBytes, magicByteSequence, 8);
  432. #if kCMDefaultEndian
  433.     /* little endian machine */
  434.     if ((theLabel.flags & kCMLittleEndianTwin) == 0) {
  435. #else
  436.     /* big endian machine */
  437.     if (theLabel.flags & kCMLittleEndianTwin) {
  438. #endif
  439.         fReverseEndian = kODTrue;
  440.         *flags = ODFlipShort(theLabel.flags);
  441.         *bufSize = ODFlipShort(theLabel.bufSize);
  442.         *majorVersion = ODFlipShort(theLabel.majorVersion);
  443.         *minorVersion = ODFlipShort(theLabel.minorVersion);
  444.         *tocOffset = ODFlipLong(theLabel.tocOffset);
  445.         *tocSize = ODFlipLong(theLabel.tocSize);
  446.     }
  447.     else {
  448.         *flags = (CMContainerFlags)theLabel.flags;
  449.         *bufSize = (CM_USHORT)theLabel.bufSize;
  450.         *majorVersion = (CM_USHORT)theLabel.majorVersion;
  451.         *minorVersion = (CM_USHORT)theLabel.minorVersion;
  452.         *tocOffset = (CMSize)theLabel.tocOffset;
  453.         *tocSize = (CMSize)theLabel.tocSize;
  454.     }
  455. }
  456.  
  457. void ODEmbeddedHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  458.                                         CMContainerFlags flags, CM_USHORT bufSize,
  459.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  460.                                         CMSize tocOffset, CMSize tocSize)
  461. {
  462.     ODULong            labelSize;
  463.     ContainerLabelFmt    theLabel;
  464.  
  465.     /* Fill in the label buffer with the info...                                                                                    */
  466.     
  467.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  468.     if (fReverseEndian) {
  469.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  470.         theLabel.bufSize = ODFlipShort(bufSize);
  471.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  472.         theLabel.minorVersion = ODFlipShort(minorVersion);
  473.         theLabel.tocOffset = ODFlipLong(tocOffset);
  474.         theLabel.tocSize = ODFlipLong(tocSize);
  475.     }
  476.     else {
  477.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  478.         theLabel.bufSize = (ODUShort)bufSize;
  479.         theLabel.majorVersion = (ODUShort)majorVersion; 
  480.         theLabel.minorVersion = (ODUShort)minorVersion;
  481.         theLabel.tocOffset = (ODULong)tocOffset;
  482.         theLabel.tocSize = (ODULong)tocSize;
  483.     }
  484.     
  485.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  486.  
  487.     /* Write the label to the end of the embedded container value...*/
  488.     
  489.     this->SeekHandler(0, kCMSeekEnd);
  490.     labelSize = (ODULong) this->WriteHandler((CMPtr) &theLabel,
  491.                                             (CMSize) sizeof(unsigned char),
  492.                                             (CMCount) sizeof(ContainerLabelFmt));
  493.  
  494.     if (labelSize != sizeof(ContainerLabelFmt))
  495.         THROW(kODErrBentoErr);
  496. }
  497.  
  498. CMValue ODEmbeddedHandlers::ReturnParentValueHandler()
  499. {
  500.     return fParentValue;
  501. }
  502.  
  503. CM_UCHAR* ODEmbeddedHandlers::ReturnContainerNameHandler()
  504. {
  505.     return ((CM_UCHAR *) fTypeName);
  506. }
  507.  
  508. CMType ODEmbeddedHandlers::ReturnTargetTypeHandler(CMContainer container)
  509. {
  510.     CMType indirectType;
  511.     
  512.     CMSetMetaHandler(fSession,
  513.                     kODIndirectValueGlobalName,
  514.                     IndirectDynamicValueMetahandler);
  515.     indirectType = CMRegisterType(container, kODIndirectValueGlobalName);
  516.                         
  517.     return indirectType;
  518. }
  519.  
  520. void ODEmbeddedHandlers::ExtractDataHandler(CMDataBuffer buffer,
  521.                                                  CMSize size, CMPrivateData data)
  522. {
  523.     ODBoolean    reverseEndian = fReverseEndian;
  524.     
  525.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  526.         size = -(long)size;
  527.         reverseEndian = kODFalse;
  528.     }
  529.     
  530.     if (reverseEndian)
  531.         ODFlipMove(buffer, data, (size_t)size);
  532.     else
  533.         ODBlockMove(buffer, data, (size_t)size);
  534. }
  535.  
  536. void ODEmbeddedHandlers::FormatDataHandler(CMDataBuffer buffer,
  537.                                      CMSize size, CMPrivateData data)
  538. {
  539.     ODBoolean    reverseEndian = fReverseEndian;
  540.     
  541.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  542.         size = -(long)size;
  543.         reverseEndian = kODFalse;
  544.     }
  545.     
  546.     if (reverseEndian)
  547.         ODFlipMove(data, buffer, (size_t)size);
  548.     else
  549.         ODBlockMove(data, buffer, (size_t)size);
  550. }
  551.